home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1999 / MacHack 1999.toast / Papers / atomicity / Code / atomicity.c next >
Encoding:
C/C++ Source or Header  |  1999-06-25  |  40.5 KB  |  1,294 lines  |  [TEXT/CWIE]

  1. /****************************************************************************************
  2.     atomicity.c
  3.     
  4.         The grabbing hands
  5.             grab all they can.
  6.         Everything counts
  7.             in large amounts.
  8.     
  9.     Copyright © 1998-1999 Red Shed Software. All rights reserved.
  10.     by Jonathan 'Wolf' Rentzsch (jon@redshed.net)
  11.     This code requires a 68020 or later or any PowerPC.
  12.     
  13.     Commenter    Date                Comment
  14.     ---------    -----------------    -----------------------------------------------------
  15.     wolf        Mon, Oct 26, 1998    Created as AtomicStacks.h/AtomicStacks.c.
  16.     wolf        Mon, Nov 9, 1998    PowerPC code rolled in.
  17.     wolf        Wed, Nov 18, 1998    Rolled in AtomicQueue code.
  18.                                     
  19.                                     Renamed to AtomicLists.h/AtomicLists.c.
  20.     wolf        Mon, Nov 23, 1998    Added guarded lists code.
  21.     wolf        Wed, Nov 25, 1998    Added ___Off functions and ___Type macros.
  22.                                     
  23.                                     Reworked file to be more comprehensible &
  24.                                     navigatible.
  25.     wolf        Mon, Nov 30, 1998    PushGuardedAtomicStack() was modified to be atomic.
  26.     wolf        Wed, Dec 2, 1998    Added requirement checking.
  27.     wolf        Thu, Dec 24, 1998    Added StealGuardedAtomicStackType() macro.
  28.     wolf        Tue, Mar 23, 1999    Added conditionally compiled 'extern "C" {}'
  29.                                     declaration.
  30.     wolf        Mon, Mar 29, 1999    Added Open Transport compatibility options.
  31.                                     
  32.                                     Now uses size_t and offsetof() instead of long and
  33.                                     my offof() macro, respectively.
  34.                                     
  35.                                     Renamed to atomicity.h/atomicity.c.
  36.     wolf        Wed, Mar 31, 1999    Reworked OpenTransport compatibility & documented it.
  37.                                     
  38.                                     Added AtomicLocks.
  39.                                     
  40.                                     Now can stand without require.h (just comment it out
  41.                                     in atomicity.c).
  42.                                     
  43.                                     The new public AtomicLocks code obsoleted my private
  44.                                     IncrementGuardedAtomicStack() function, so the
  45.                                     function has been removed and the Guarded Stack (and
  46.                                     thus the Guarded Queue) code has been moved to Atomic
  47.                                     Locks.
  48.     wolf        Thu, Apr 15, 1999    Added Peek[Guarded]AtomicQueue[Off|Type]().
  49.     wolf        Thu, Apr 22, 1999    Moved the OpenTransport compatibility settings into
  50.                                     their own file: atomicity.config.h.
  51.     wolf        Fri, Apr 30, 1999    Added Peek[Guarded]AtomicStack[Off|Type].
  52.     wolf        Mon, May 3, 1999    Changed name of AtomicQueue's fields from (pushed,
  53.                                     toPop) to (input, output) to ease understanding.
  54.                                     
  55.                                     Rearranged the parameter order of the ___Off and
  56.                                     ___Type functions. Before it was ( OFFSET, STACK )
  57.                                     and ( STRUCTURE, FIELD, STACK ). Now it's
  58.                                     ( STACK, OFFSET ) and ( STACK, STRUCTURE, FIELD ).
  59.                                     This breaks existing code, but the fix is simple and
  60.                                     the new way is easier to remember. I wanted to make
  61.                                     this change before I distributed my code on the
  62.                                     MacHack 99 CD-ROM.
  63.     wolf        Fri, May 7, 1999    The Open Transport Compatibility Options weren't
  64.                                     working correctly for some reason (apparently my
  65.                                     concepts about what !defined() means is wrong).
  66.                                     I reworked it a little and now all is well.
  67.     
  68.     ************************************************************************************/
  69.  
  70. #include    "atomicity.h"
  71. #include    "require.h"    //    Comment out this line to disable requirement checking.
  72.  
  73. #ifndef    GenerateRequirements
  74.     #define    Require( CODE )
  75.     #define    RequirePtr( PTR )
  76.     #define    RequirePtrAlign( PTR, ALIGN )
  77.     #define    RequirePtrAlignIfNotNil( PTR, ALIGN )
  78. #endif
  79.  
  80. #if        defined(DontUseOpenTransport)
  81. #elif    defined(OnlyUseOpenTransport)
  82. #else    //    UseOpenTransportIfAvailable
  83.     Boolean
  84. IsOpenTransportAvailable();
  85. #endif
  86.  
  87. /****************************************************************************************
  88. *    
  89. *    Atomic Stack Functions
  90. *    
  91. ****************************************************************************************/
  92. #pragma mark    --Atomic Stack Functions--
  93.  
  94. /****************************************************************************************
  95.     About the next three functions (MyPushAtomicStack(), MyPopAtomicStack() &
  96.     MyStealAtomicStack()):
  97.     
  98.     These functions are written in assembly language to access atomic instructions
  99.     inaccessable from a high-level language like C. We want to compile to differing
  100.     platforms from a single source file, so we use conditional #defines to generate
  101.     68K or PowerPC code depending on what the compiler is generating.
  102.     
  103.     In addition to conditionally generating 68K or PowerPC assembly, when generating 68K
  104.     code, we conditionally generate Classic 68K or CFM-68K code.
  105.     
  106.     Classic 68K:
  107.         Classic 68K doesn't define a standard parameter passing convention, so we use
  108.         the Pascal calling convention. We use the 'pascal' keyword so the compiler
  109.         generates code that uses the Pascal calling convention.
  110.         
  111.         The Pascal calling convention requires the caller make space for the callee's
  112.         result (if any) and all parameters. The parameters are pushed from left to right,
  113.         followed by the return address. The callee is responsible for popping all
  114.         paramaters before returning to the caller. The function result (if any) is left
  115.         on the stack.
  116.         
  117.         The Pascal calling convention doesn't explictly state what registers should be
  118.         saved, so we use the rather strict CFM-68K register preservation guideline, which
  119.         requires we preserve registers d3-d7 and a2-a7. That leaves us with d0, d1, d2
  120.         and a0, a1.
  121.     CFM-68K:
  122.         CFM-68K defines a standard parameter passing convention, so the 'pascal'
  123.         keyword (required when generating Classic 68K code) is ignored.
  124.         
  125.         Under CFM-68K, parameters are pushed from right to left onto the stack,
  126.         followed by the return address. The function's result (if any) is returned
  127.         in register D0. CFM-68K requires we preserve registers d3-d7 and a2-a7. That
  128.         leaves us with d0, d1, d2 and a0, a1.
  129.     PowerPC:
  130.         PowerPC code always uses CFM parameter passing conventions, so the 'pascal'
  131.         keyword (required when generating Classic 68K code) is ignored.
  132.         
  133.         Under PowerPC, parameters are passed in registers left to right, starting with
  134.         register r3. The function's result (if any) is stored in register r3.
  135.     
  136.     ************************************************************************************/
  137.  
  138. /****************************************************************************************
  139.     Commenter    Date                Comment
  140.     ---------    -----------------    -----------------------------------------------------
  141.     wolf        Mon, Oct 26, 1998    Created.
  142.     wolf        Mon, Nov 9, 1998    PowerPC code rolled in.
  143.     wolf        Tue, Mar 23, 1999    Rewrote PowerPC code. After more study of the
  144.                                     programming model, I learned I need not save and
  145.                                     restore the Link Register (I don't modify it) and
  146.                                     the Condition Register (the cr0 field is marked
  147.                                     volatile). This saves 8 instructions including
  148.                                     two loads and two stores.
  149.                                     However, I now use a more complex double-load-with-
  150.                                     sync technique to eliminate the possibility of
  151.                                     livelock in a multiprocessor environment. The
  152.                                     overhead of the sync instruction probably negates
  153.                                     the speed gain of omitting the 8 instructions.
  154.     wolf        Thu, Apr 1, 1999    Rewrote PowerPC code to be a tad more efficient.
  155.     
  156.     In C:
  157.         AtomicElement    *next = stack->next;
  158.         element->next = next;
  159.         stack->next = element;
  160.     
  161.     ************************************************************************************/
  162.  
  163.     asm
  164.     pascal
  165.     void
  166. MyPushAtomicStack(
  167.     AtomicElement    *element,
  168.     AtomicStack        *stack )
  169. {
  170. #if            powerc
  171.     //-------------------------------------------------
  172.     //    PowerPC
  173. lostReservation:
  174.     lwz        r5, 0(r4)        //    next1 = stack->next.
  175.     stw        r5, 0(r3)        //    element->next = next1.
  176.     lwarx    r6, 0, r4        //    next2 = stack->next.
  177.     cmpw    r6, r5            //    If next1 != next2
  178.     bne-    nextChanged        //    Then someone else progressed, try again.
  179.     sync                    //    Let the store settle.
  180.     stwcx.    r3, 0, r4        //    If stack->next didn't change, stack->next = element.
  181.     bne-    lostReservation    //    Else someone else progressed, try again.
  182.     sync                    //    Broadcast update.
  183.     blr                        //    We're outta here.
  184. nextChanged:
  185.     sync                    //    Let the store settle.
  186.     stwcx.    r6, 0, r4        //    Clear reservation created above.
  187.     b        lostReservation    //    Try again.
  188. #else    //    powerc
  189. #if            GENERATINGCFM
  190.     //-------------------------------------------------
  191.     //    CFM-68K
  192.     movea.l    8(a7), a0        //    stack.
  193.     movea.l    4(a7), a1        //    element.
  194.     move.l    a1, d0            //    element.
  195. again:
  196.     move.l    (a0), d1        //    next = stack->next.
  197.     move.l    d1, (a1)        //    element->next = next.
  198.     dc.l    0x0ED00001        //    CWPro2 doesn't know cas. Here's the raw opcode.
  199. //    cas.l    d1, d0, (a0)    //    If stack->next didn't change, stack->next = element.
  200.     bne.s    again            //    Else someone else progressed, try again.
  201.     movea.l    (a7)+, a0        //    Pop the return address.
  202.     addq.l    #8, a7            //    Pop the parameters.
  203.     jmp        (a0)            //    We're outta here.
  204. #else    //    GENERATINGCFM
  205.     //-------------------------------------------------
  206.     //    Classic 68K
  207.     movea.l    4(a7), a0        //    stack.
  208.     movea.l    8(a7), a1        //    element.
  209.     move.l    a1, d0            //    element.
  210. again:
  211.     move.l    (a0), d1        //    next = stack->next.
  212.     move.l    d1, (a1)        //    element->next = next.
  213.     dc.l    0x0ED00001        //    CWPro2 doesn't know cas. Here's the raw opcode.
  214. //    cas.l    d1, d0, (a0)    //    If stack->next didn't change, stack->next = element.
  215.     bne.s    again            //    Else someone else progressed, try again.
  216.     movea.l    (a7)+, a0        //    Pop the return address.
  217.     addq.l    #8, a7            //    Pop the parameters.
  218.     jmp        (a0)            //    We're outta here.
  219. #endif    //    GENERATINGCFM
  220. #endif    //    powerc
  221. }
  222.  
  223. /****************************************************************************************
  224.     Commenter    Date                Comment
  225.     ---------    -----------------    -----------------------------------------------------
  226.     wolf        Mon, Oct 26, 1998    Created.
  227.     wolf        Mon, Nov 9, 1998    PowerPC code rolled in.
  228.     wolf        Wed, Nov 25, 1998    Fixed function result bug in Classic 68K code.
  229.                                     I was returning the result in the space allocated
  230.                                     for the stack parameter, not the result space right
  231.                                     above it.
  232.     wolf        Tue, Mar 23, 1999    Rewrote PowerPC code. After more study of the
  233.                                     programming model, I learned I need not save and
  234.                                     restore the Link Register (I don't modify it) and
  235.                                     the Condition Register (the cr0 field is marked
  236.                                     volatile). This saves 8 instructions including
  237.                                     two loads and two stores.
  238.     wolf        Thu, Apr 1, 1999    I moved the test for a nil stack out of the
  239.                                     reservation code, which should help performance.
  240.     
  241.     In C:
  242.         AtomicElement    *next, *element = stack->next;
  243.         if( element != nil ) {
  244.             next = element->next;
  245.             stack->next = next;
  246.         }
  247.         return( element );
  248.     
  249.     ************************************************************************************/
  250.  
  251.     asm
  252.     pascal
  253.     AtomicElement*
  254. MyPopAtomicStack(
  255.     AtomicStack        *stack )
  256. {
  257. #if            powerc
  258.     //-------------------------------------------------
  259.     //    PowerPC
  260. lostReservation:
  261.     lwz        r4, 0(r3)        //    element1 = stack->next.
  262.     cmpwi    r4, 0            //    If element1 == nil
  263.     beq        emptyStack        //    Then the stack is empty, return nil.
  264.     
  265.     lwarx    r5, 0, r3        //    element2 = stack->next.
  266.     cmpw    r5, r4            //    If element1 != element2
  267.     bne-    stackChanged    //    Then someone else progressed, try again.
  268.     lwz        r6, 0(r5)        //    next = element2->next.
  269.     stwcx.    r6, 0, r3        //    If the reservation wasn't lost, stack->next = next,
  270.     bne-    lostReservation    //    Else someone else progressed, try again.
  271.     sync                    //    Broadcast update.
  272.     mr        r3, r4            //    element is in r4, but the result must be in r3. Move it.
  273.     blr                        //    We're outta here.
  274. stackChanged:
  275.     stwcx.    r5, 0, r3        //    Clear reservation created above.
  276.     b        lostReservation    //    Try again.
  277. emptyStack:
  278.     mr        r3, r4            //    element is in r4, but the result must be in r3. Move it.
  279.     blr                        //    We're outta here.
  280. #else    //    powerc
  281. #if            GENERATINGCFM
  282.     //-------------------------------------------------
  283.     //    CFM-68K
  284.     movea.l    4(a7), a0        //    stack.
  285. again:
  286.     movea.l    (a0), a1        //    element = stack->next.
  287.     move.l    a1, d0            //    element = stack->next.
  288.     tst.l    d0                //    Is element == nil?
  289.     beq.s    done            //    If equal, return nil.
  290.     move.l    (a1), d1        //    next = element->next.
  291.     dc.l    0xED00040        //    CWPro2 doesn't know cas. Here's the raw opcode.
  292. //    cas.l    d0, d1, (a0)    //    If stack->next wasn't changed, stack->next = next.
  293.     bne.s    again            //    Else someone else progressed, try again.
  294. done:
  295.     movea.l    (a7)+, a0        //    Pop the return address.
  296.     addq.l    #4, a7            //    Pop stack parameter.
  297.     jmp        (a0)            //    We're outta here.
  298. #else    //    GENERATINGCFM
  299.     //-------------------------------------------------
  300.     //    Classic 68K
  301.     movea.l    4(a7), a0        //    stack.
  302. again:
  303.     movea.l    (a0), a1        //    element = stack->next.
  304.     move.l    a1, d0            //    element = stack->next.
  305.     tst.l    d0                //    Is element == nil?
  306.     beq.s    done            //    If equal, return nil.
  307.     move.l    (a1), d1        //    next = element->next.
  308.     dc.l    0xED00040        //    CWPro2 doesn't know cas. Here's the raw opcode.
  309. //    cas.l    d0, d1, (a0)    //    If stack->next wasn't changed, stack->next = next.
  310.     bne.s    again            //    Else someone else progressed, try again.
  311. done:
  312.     movea.l    (a7)+, a0        //    Pop the return address.
  313.     addq.l    #4, a7            //    Pop stack parameter.
  314.     move.l    d0, (a7)        //    Return the popped element on the stack.
  315.     jmp        (a0)            //    We're outta here.
  316. #endif    //    GENERATINGCFM
  317. #endif    //    powerc
  318. }
  319.  
  320. /****************************************************************************************
  321.     Commenter    Date                Comment
  322.     ---------    -----------------    -----------------------------------------------------
  323.     wolf        Mon, Oct 26, 1998    Created.
  324.     wolf        Mon, Nov 9, 1998    PowerPC code rolled in.
  325.     wolf        Wed, Nov 25, 1998    Fixed function result bug in Classic 68K code.
  326.                                     I was returning the result in the space allocated
  327.                                     for the stack parameter, not the result space right
  328.                                     above it.
  329.     wolf        Thu, Mar 4, 1999    On the PowerPC side, I mistakenly moved r4 (which
  330.                                     is always set to nil) into the result register, r3.
  331.                                     This resulted in StealAtomicStack() always returning
  332.                                     nil when executing PowerPC. Now I correctly move r5
  333.                                     into r3.
  334.                                     It's very strange that I didn't catch this obvious
  335.                                     error in my test matrix. Perhaps I forgot to test the
  336.                                     PowerPC side and only tested the 68K sides.
  337.     wolf        Thu, Apr 1, 1999    I moved the test for a nil stack out of the
  338.                                     reservation code, which should help performance.
  339.     
  340.     In C:
  341.         AtomicElement    *result = stack->next;
  342.         stack->next = nil;
  343.         return( result );
  344.     
  345.     ************************************************************************************/
  346.  
  347.     asm
  348.     pascal
  349.     AtomicElement*
  350. MyStealAtomicStack(
  351.     AtomicStack        *stack )
  352. {
  353. #if            powerc
  354.     //-------------------------------------------------
  355.     //    PowerPC
  356.     li        r4, 0
  357. lostReservation:
  358.     lwz        r5, 0(r3)        //    result1 = stack->next.
  359.     cmpwi    r5, 0            //    If result1 == nil
  360.     beq        emptyStack        //    Then the stack is empty, return nil.
  361.     
  362.     lwarx    r6, 0, r3        //    result2 = stack->next.
  363.     cmpw    r6, r5            //    If result1 != result2
  364.     bne-    stackChanged    //    Then someone else progressed, retry.
  365.     stwcx.    r4, 0, r3        //    If the reservation wasn't lost, stack->next = nil
  366.     bne-    lostReservation    //    Else someone else progressed, try again.
  367.     sync                    //    Broadcast update.
  368.     mr        r3, r5            //    element is in r4, but the result must be in r3. Move it.
  369.     blr                        //    We're outta here.
  370. stackChanged:
  371.     stwcx.    r6, 0, r3        //    Clear reservation created above.
  372.     b        lostReservation    //    Try again.
  373. emptyStack:
  374.     mr        r3, r4            //    Return nil.
  375.     blr                        //    We're outta here.
  376. #else    //    powerc
  377. #if            GENERATINGCFM
  378.     //-------------------------------------------------
  379.     //    CFM-68K
  380.     movea.l    4(a7), a0        //    stack.
  381.     moveq.l    #0, d1
  382. again:
  383.     move.l    (a0), d0        //    element = stack->next.
  384.     dc.l    0xED00040        //    CWPro2 doesn't know cas. Here's the raw opcode.
  385. //    cas.l    d0, d1, (a0)    //    If stack->next wasn't changed, stack->next = nil.
  386.     bne.s    again            //    Else someone else progressed, try again.
  387.     
  388.     movea.l    (a7)+, a0        //    Pop the return address.
  389.     addq.l    #4, a7            //    Pop stack parameter.
  390.     jmp        (a0)            //    We're outta here.
  391. #else    //    GENERATINGCFM
  392.     //-------------------------------------------------
  393.     //    Classic 68K
  394.     movea.l    4(a7), a0        //    stack.
  395.     moveq.l    #0, d1
  396. again:
  397.     move.l    (a0), d0        //    element = stack->next.
  398.     dc.l    0xED00040        //    CWPro2 doesn't know cas. Here's the raw opcode.
  399. //    cas.l    d0, d1, (a0)    //    If stack->next wasn't changed, stack->next = nil.
  400.     bne.s    again            //    Else someone else progressed, try again.
  401.     
  402.     movea.l    (a7)+, a0        //    Pop the return address.
  403.     addq.l    #4, a7            //    Pop the stack parameter.
  404.     move.l    d0, (a7)        //    Return the popped element on the stack.
  405.     jmp        (a0)            //    We're outta here.
  406. #endif    //    GENERATINGCFM
  407. #endif    //    powerc
  408. }
  409.  
  410. /****************************************************************************************
  411.     Commenter    Date                Comment
  412.     ---------    -----------------    -----------------------------------------------------
  413.     wolf        Fri, Apr 30, 1999    Created.
  414.     
  415.     ************************************************************************************/
  416.  
  417.     pascal
  418.     AtomicElement*
  419. PeekAtomicStack(
  420.     AtomicStack        *stack )
  421. {
  422.     RequirePtrAlign( stack, 4 );
  423.     
  424.     return( stack->next );
  425. }
  426.  
  427. /****************************************************************************************
  428. *    
  429. *    Atomic Stack Offset Functions
  430. *    
  431. ****************************************************************************************/
  432. #pragma mark    -
  433. #pragma mark    --Atomic Stack Offset Functions--
  434.  
  435. /****************************************************************************************
  436.     Commenter    Date                Comment
  437.     ---------    -----------------    -----------------------------------------------------
  438.     wolf        Wed, Nov 25, 1998    Created.
  439.     
  440.     ************************************************************************************/
  441.  
  442.     pascal
  443.     void
  444. PushAtomicStackOff(
  445.     void            *element,
  446.     AtomicStack        *stack,
  447.     size_t            offset )
  448. {
  449.     RequirePtrAlign( element, 4 );
  450.     Require( offset < 0xFFFF );
  451.     RequirePtrAlign( stack, 4 );
  452.     
  453.     PushAtomicStack( (AtomicElement*) (((char*) element) + offset), stack );
  454. }
  455.  
  456. /****************************************************************************************
  457.     Commenter    Date                Comment
  458.     ---------    -----------------    -----------------------------------------------------
  459.     wolf        Wed, Nov 25, 1998    Created.
  460.     
  461.     ************************************************************************************/
  462.  
  463.     pascal
  464.     AtomicElement*
  465. PopAtomicStackOff(
  466.     AtomicStack        *stack,
  467.     size_t            offset )
  468. {
  469.     AtomicElement    *result;
  470.     
  471.     Require( offset < 0xFFFF );
  472.     RequirePtrAlign( stack, 4 );
  473.     
  474.     result = PopAtomicStack( stack );
  475.     
  476.     if( result )
  477.         result = (AtomicElement*) (((char*) result) - offset);
  478.     
  479.     RequirePtrAlignIfNotNil( result, 4 );
  480.     return( result );
  481. }
  482.  
  483. /****************************************************************************************
  484.     Commenter    Date                Comment
  485.     ---------    -----------------    -----------------------------------------------------
  486.     wolf        Wed, Nov 25, 1998    Created.
  487.     
  488.     ************************************************************************************/
  489.  
  490.     pascal
  491.     AtomicElement*
  492. StealAtomicStackOff(
  493.     AtomicStack        *stack,
  494.     size_t            offset )
  495. {
  496.     AtomicElement    *result;
  497.     
  498.     Require( offset < 0xFFFF );
  499.     RequirePtrAlign( stack, 4 );
  500.     
  501.     result = StealAtomicStack( stack );
  502.     
  503.     if( result )
  504.         result = (AtomicElement*) (((char*) result) - offset);
  505.     
  506.     RequirePtrAlignIfNotNil( result, 4 );
  507.     return( result );
  508. }
  509.  
  510. /****************************************************************************************
  511.     Commenter    Date                Comment
  512.     ---------    -----------------    -----------------------------------------------------
  513.     wolf        Fri, Apr 30, 1999    Created.
  514.     
  515.     ************************************************************************************/
  516.  
  517.     pascal
  518.     AtomicElement*
  519. PeekAtomicStackOff(
  520.     AtomicStack        *stack,
  521.     size_t            offset )
  522. {
  523.     AtomicElement    *result;
  524.     
  525.     Require( offset < 0xFFFF );
  526.     RequirePtrAlign( stack, 4 );
  527.     
  528.     result = PeekAtomicStack( stack );
  529.     
  530.     if( result )
  531.         result = (AtomicElement*) (((char*) result) - offset);
  532.     
  533.     RequirePtrAlignIfNotNil( result, 4 );
  534.     return( result );
  535. }
  536.  
  537. /****************************************************************************************
  538. *    
  539. *    Atomic Lock Functions
  540. *    
  541. ****************************************************************************************/
  542. #pragma mark    -
  543. #pragma mark    --Atomic Lock Functions--
  544.  
  545. /****************************************************************************************
  546.     Commenter    Date                Comment
  547.     ---------    -----------------    -----------------------------------------------------
  548.     wolf        Wed, Mar 31, 1999    Created.
  549.     wolf        Thu, Apr 1, 1999    I moved the test for a nonzero lock out of the
  550.                                     reservation code, which should help performance.
  551.     
  552.     In C:
  553.     
  554.     if( *lock == 0 ) {
  555.         *lock = 1;
  556.         return( true );
  557.     } else
  558.         return( false );
  559.     
  560.     ************************************************************************************/
  561.  
  562.     asm
  563.     pascal
  564.     long
  565. MyGrabAtomicLock(
  566.     AtomicLock    *lock )
  567. {
  568. #if            powerc
  569.     //-------------------------------------------------
  570.     //    PowerPC
  571.     li        r4, 1
  572. lostReservation:
  573.     lwz        r5, 0(r3)        //    result1 = *lock.
  574.     cmpwi    r5, 0            //    If result != 0
  575.     bne        notZero            //    Then return false.
  576.     
  577.     lwarx    r6, 0, r3        //    result2 = *lock.
  578.     cmpw    r5, r6            //    If result1 != result2
  579.     bne-    notEqual        //    Then someone else progressed, try again.
  580.     stwcx.    r4, 0, r3        //    If the reservation wasn't lost, *lock = 1
  581.     bne-    lostReservation    //    Else someone else progressed, try again.
  582.     sync                    //    Broadcast update.
  583.     li        r3, 1            //    Return true.
  584.     blr                        //    We're outta here.
  585. notEqual:
  586.     stwcx.    r6, 0, r3        //    Clear reservation created above.
  587.     b        lostReservation    //    Try again.
  588. notZero:
  589.     li        r3, 0            //    Return false.
  590.     blr                        //    We're outta here.
  591. #else    //    powerc
  592. #if            GENERATINGCFM
  593.     //-------------------------------------------------
  594.     //    CFM-68K
  595.     movea.l    (a7)+, a1        //    Pop the return address.
  596.     movea.l    (a7)+, a0        //    Pop lock parameter.
  597.     moveq.l    #0, d0            //    0.
  598.     moveq.l    #1, d1            //    1.
  599.     dc.l    0xED00040        //    CWPro2 doesn't know cas. Here's the raw opcode.
  600. //    cas.l    d0, d1, (a0)    //    If *lock == 0 then *lock = 1.
  601.     bne        fail
  602.     moveq.l    #1, d0            //    Return true in register d0.
  603.     jmp        (a1)            //    We're outta here.
  604. fail:
  605.     moveq.l    #0, d0            //    Return false in register d0.
  606.     jmp        (a1)            //    We're outta here.
  607. #else    //    GENERATINGCFM
  608.     //-------------------------------------------------
  609.     //    Classic 68K
  610.     movea.l    (a7)+, a1        //    Pop the return address.
  611.     movea.l    (a7)+, a0        //    Pop lock parameter.
  612.     moveq.l    #0, d0            //    0.
  613.     moveq.l    #1, d1            //    1.
  614.     dc.l    0xED00040        //    CWPro2 doesn't know cas. Here's the raw opcode.
  615. //    cas.l    d0, d1, (a0)    //    If *lock == 0 then *lock = 1.
  616.     bne        fail
  617.     move.l    #1, (a7)        //    Return true on the stack.
  618.     jmp        (a1)            //    We're outta here.
  619. fail:
  620.     move.l    #0, (a7)        //    Return false on the stack.
  621.     jmp        (a1)            //    We're outta here.
  622. #endif    //    GENERATINGCFM
  623. #endif    //    powerc
  624. }
  625.  
  626. /****************************************************************************************
  627.     Commenter    Date                Comment
  628.     ---------    -----------------    -----------------------------------------------------
  629.     wolf        Tue, Mar 23, 1999    Created.
  630.     
  631.     ************************************************************************************/
  632.  
  633.     void
  634. ReleaseAtomicLock(
  635.     AtomicLock    *lock )
  636. {
  637.     RequirePtrAlign( lock, 4 );
  638.     *lock = 0;
  639. }
  640.  
  641. /****************************************************************************************
  642. *    
  643. *    Open Transport Compatibility Layer
  644. *
  645. *    The the following four functions (PushAtomicStack, PopAtomicStack, StealAtomicStack
  646. *    and IsOpenTransportAvailable) are only compiled if UseOpenTransportIfAvailable is
  647. *    defined. Otherwise zero-runtime-overhead macros are used.
  648. *    
  649. ****************************************************************************************/
  650. #pragma mark    -
  651. #pragma mark    --Open Transport Compatibility Layer--
  652.  
  653. #if        defined(DontUseOpenTransport)
  654. #elif    defined(OnlyUseOpenTransport)
  655. #else    //    UseOpenTransportIfAvailable
  656.  
  657. /****************************************************************************************
  658.     Commenter    Date                Comment
  659.     ---------    -----------------    -----------------------------------------------------
  660.     wolf        Mon, Mar 29, 1999    Created.
  661.     
  662.     ************************************************************************************/
  663.  
  664.     void
  665. PushAtomicStack(
  666.     AtomicElement    *element,
  667.     AtomicStack        *stack )
  668. {
  669.     RequirePtrAlign( element, 4 );
  670.     RequirePtrAlign( stack, 4 );
  671.     
  672.     if( IsOpenTransportAvailable() )
  673.         OTLIFOEnqueue( (OTLIFO*) stack, (OTLink*) element );
  674.     else
  675.         MyPushAtomicStack( element, stack );
  676. }
  677.  
  678. /****************************************************************************************
  679.     Commenter    Date                Comment
  680.     ---------    -----------------    -----------------------------------------------------
  681.     wolf        Mon, Mar 29, 1999    Created.
  682.     
  683.     ************************************************************************************/
  684.  
  685.     AtomicElement*
  686. PopAtomicStack(
  687.     AtomicStack    *stack )
  688. {
  689.     AtomicElement    *result;
  690.     
  691.     RequirePtrAlign( stack, 4 );
  692.     
  693.     if( IsOpenTransportAvailable() )
  694.         result = (AtomicElement*) OTLIFODequeue( (OTLIFO*) stack );
  695.     else
  696.         result = MyPopAtomicStack( stack );
  697.     
  698.     RequirePtrAlignIfNotNil( result, 4 );
  699.     return( result );
  700. }
  701.  
  702. /****************************************************************************************
  703.     Commenter    Date                Comment
  704.     ---------    -----------------    -----------------------------------------------------
  705.     wolf        Mon, Mar 29, 1999    Created.
  706.     
  707.     ************************************************************************************/
  708.  
  709.     AtomicElement*
  710. StealAtomicStack(
  711.     AtomicStack    *stack )
  712. {
  713.     AtomicElement    *result;
  714.     
  715.     RequirePtrAlign( stack, 4 );
  716.     
  717.     if( IsOpenTransportAvailable() )
  718.         result = (AtomicElement*) OTLIFOStealList( (OTLIFO*) stack );
  719.     else
  720.         result = MyStealAtomicStack( stack );
  721.     
  722.     RequirePtrAlignIfNotNil( result, 4 );
  723.     return( result );
  724. }
  725.  
  726. /****************************************************************************************
  727.     Commenter    Date                Comment
  728.     ---------    -----------------    -----------------------------------------------------
  729.     wolf        Wed, Mar 31, 1999    Created.
  730.     
  731.     ************************************************************************************/
  732.  
  733.     Boolean
  734. GrabAtomicLock(
  735.     AtomicLock    *lock )
  736. {
  737.     Boolean    result;
  738.     
  739.     RequirePtrAlign( lock, 4 );
  740.     
  741.     if( IsOpenTransportAvailable() )
  742.         result = OTCompareAndSwap32( 0, 1, lock );
  743.     else
  744.         result = MyGrabAtomicLock( lock );
  745.     
  746.     return( result );
  747. }
  748.  
  749. /****************************************************************************************
  750.     Commenter    Date                Comment
  751.     ---------    -----------------    -----------------------------------------------------
  752.     wolf        Mon, Mar 29, 1999    Created.
  753.     
  754.     ************************************************************************************/
  755.  
  756.     Boolean
  757. IsOpenTransportAvailable()
  758. {
  759.     static    OSErr    err = 1;
  760.     long    ignored;
  761.     
  762.     if( err == 1 ) {
  763.         err = Gestalt( gestaltOpenTpt, &ignored );
  764.         if( !err && OTLIFOEnqueue == nil )
  765.             err = -1;
  766.     }
  767.     
  768.     return( err ? false : true );
  769. }
  770.  
  771. #endif    //    UseOpenTransportIfAvailable
  772.  
  773. /****************************************************************************************
  774. *    
  775. *    Guarded Atomic Stack Functions
  776. *    
  777. ****************************************************************************************/
  778. #pragma mark    -
  779. #pragma mark    --Guarded Atomic Stack Functions--
  780.  
  781. /****************************************************************************************
  782.     Commenter    Date                Comment
  783.     ---------    -----------------    -----------------------------------------------------
  784.     wolf        Mon, Nov 23, 1998    Created.
  785.     wolf        Mon, Nov 30, 1998    Broke out element count incrementing code into its
  786.                                     own atomic function: IncrementGuardedAtomicStack().
  787.                                     It takes three instructions to increment a value in
  788.                                     memory on a PowerPC, so we need to use the special
  789.                                     syncronization instructions offered by the PowerPC.
  790.     wolf        Wed, Mar 31, 1999    Migrated to Atomic Locks.
  791.     
  792.     ************************************************************************************/
  793.  
  794.     pascal
  795.     long
  796. PushGuardedAtomicStack(
  797.     GuardedAtomicElement    *element,
  798.     AtomicStack                *stack )
  799. {
  800.     Boolean    result = GrabAtomicLock( &element->lock );
  801.     
  802.     RequirePtrAlign( element, 4 );
  803.     RequirePtrAlign( stack, 4 );
  804.     
  805.     if( result )
  806.         PushAtomicStack( (AtomicElement*) element, stack );
  807.     return( result );
  808. }
  809.  
  810. /****************************************************************************************
  811.     Commenter    Date                Comment
  812.     ---------    -----------------    -----------------------------------------------------
  813.     wolf        Mon, Nov 23, 1998    Created.
  814.     wolf        Wed, Mar 31, 1999    Migrated to Atomic Locks.
  815.     
  816.     ************************************************************************************/
  817.  
  818.     pascal
  819.     GuardedAtomicElement*
  820. PopGuardedAtomicStack(
  821.     AtomicStack                *stack )
  822. {
  823.     GuardedAtomicElement    *result;
  824.     
  825.     RequirePtrAlign( stack, 4 );
  826.     
  827.     result = (GuardedAtomicElement*) PopAtomicStack( stack );
  828.  
  829.     if( result )
  830.         ReleaseAtomicLock( &result->lock );
  831.     
  832.     RequirePtrAlignIfNotNil( result, 4 );
  833.     return( result );
  834. }
  835.  
  836. /****************************************************************************************
  837.     Commenter    Date                Comment
  838.     ---------    -----------------    -----------------------------------------------------
  839.     wolf        Mon, May 3, 1999    Created.
  840.     
  841.     ************************************************************************************/
  842.  
  843.     pascal
  844.     GuardedAtomicElement*
  845. PeekGuardedAtomicStack(
  846.     AtomicStack        *stack )
  847. {
  848.     RequirePtrAlign( stack, 4 );
  849.     
  850.     return( (GuardedAtomicElement*) stack->next );
  851. }
  852.  
  853. /****************************************************************************************
  854. *    
  855. *    Guarded Atomic Stack Offset Functions
  856. *    
  857. ****************************************************************************************/
  858. #pragma mark    -
  859. #pragma mark    --Guarded Atomic Stack Offset Functions--
  860.  
  861. /****************************************************************************************
  862.     Commenter    Date                Comment
  863.     ---------    -----------------    -----------------------------------------------------
  864.     wolf        Wed, Nov 25, 1998    Created.
  865.     
  866.     ************************************************************************************/
  867.  
  868.     pascal
  869.     long
  870. PushGuardedAtomicStackOff(
  871.     void            *element,
  872.     AtomicStack        *stack,
  873.     size_t            offset )
  874. {
  875.     RequirePtr( element );
  876.     Require( offset < 0xFFFF );
  877.     RequirePtrAlign( stack, 4 );
  878.     
  879.     return( PushGuardedAtomicStack( (GuardedAtomicElement*) (((char*) element) + offset),
  880.                                     stack ) );
  881. }
  882.  
  883. /****************************************************************************************
  884.     Commenter    Date                Comment
  885.     ---------    -----------------    -----------------------------------------------------
  886.     wolf        Wed, Nov 25, 1998    Created.
  887.     
  888.     ************************************************************************************/
  889.  
  890.     pascal
  891.     GuardedAtomicElement*
  892. PopGuardedAtomicStackOff(
  893.     AtomicStack        *stack,
  894.     size_t            offset )
  895. {
  896.     GuardedAtomicElement    *result;
  897.     
  898.     Require( offset < 0xFFFF );
  899.     RequirePtrAlign( stack, 4 );
  900.     
  901.     result = PopGuardedAtomicStack( stack );
  902.     
  903.     if( result )
  904.         result = (GuardedAtomicElement*) (((char*) result) - offset);
  905.     
  906.     RequirePtrAlignIfNotNil( result, 4 );
  907.     return( result );
  908. }
  909.  
  910. /****************************************************************************************
  911.     Commenter    Date                Comment
  912.     ---------    -----------------    -----------------------------------------------------
  913.     wolf        Mon, May 3, 1999    Created.
  914.     
  915.     ************************************************************************************/
  916.  
  917.     pascal
  918.     GuardedAtomicElement*
  919. PeekGuardedAtomicStackOff(
  920.     AtomicStack        *stack,
  921.     size_t            offset )
  922. {
  923.     GuardedAtomicElement    *result;
  924.     
  925.     Require( offset < 0xFFFF );
  926.     RequirePtrAlign( stack, 4 );
  927.     
  928.     result = PeekGuardedAtomicStack( stack );
  929.     
  930.     if( result )
  931.         result = (GuardedAtomicElement*) (((char*) result) - offset);
  932.     
  933.     RequirePtrAlignIfNotNil( result, 4 );
  934.     return( result );
  935. }
  936.  
  937. /****************************************************************************************
  938. *    
  939. *    Atomic Queue Functions
  940. *    
  941. ****************************************************************************************/
  942. #pragma mark    -
  943. #pragma mark    --Atomic Queue Functions--
  944.  
  945. /****************************************************************************************
  946.     Commenter    Date                Comment
  947.     ---------    -----------------    -----------------------------------------------------
  948.     wolf        Wed, Nov 18, 1998    Created.
  949.     
  950.     An atomic queue is simply a queue that uses an atomic stack as its input list.
  951.     
  952.     ************************************************************************************/
  953.  
  954.     pascal
  955.     void
  956. PushAtomicQueue(
  957.     AtomicElement    *element,
  958.     AtomicQueue        *queue )
  959. {
  960.     RequirePtrAlign( element, 4 );
  961.     RequirePtrAlign( queue, 4 );
  962.     
  963.     PushAtomicStack( element, &queue->input );
  964. }
  965.  
  966. /****************************************************************************************
  967.     Commenter    Date                Comment
  968.     ---------    -----------------    -----------------------------------------------------
  969.     wolf        Wed, Nov 18, 1998    Created.
  970.     
  971.     When the client wants the next element in the queue, we try to pop the element
  972.     off the output stack. If the output stack is empty, then we have to refill the output
  973.     stack from the input stack.
  974.     
  975.     We do this by atomically "stealing" the entire stack. Once we have the stack, we
  976.     "reverse" the stack (make a first-in-last-out list into a first-in-first-out list) by
  977.     popping each element from the stolen stack and pushing it onto the output stack.
  978.     
  979.     If all this stealing, popping and pushing sounds expensive, it isn't. The reversal
  980.     operates in linear time, which is acceptable. However, if you don't need the
  981.     sequential access of a queue, by all means use a stack, as it operates in fast
  982.     constant time.
  983.     
  984.     ************************************************************************************/
  985.  
  986.     pascal
  987.     AtomicElement*
  988. PopAtomicQueue(
  989.     AtomicQueue            *queue )
  990. {
  991.     AtomicElement    *next, *current;
  992.     
  993.     RequirePtrAlign( queue, 4 );
  994.     
  995.     current = PopAtomicStack( &queue->output );
  996.     
  997.     if( current == nil ) {
  998.         //    Nothing to pop. Refill the queue from the input stack.
  999.         current = StealAtomicStack( &queue->input );
  1000.         while( current ) {
  1001.             RequirePtrAlign( current, 4 );
  1002.             next = current->next;
  1003.             PushAtomicStack( current, &queue->output );
  1004.             current = next;
  1005.         }
  1006.         current = PopAtomicStack( &queue->output );
  1007.     }
  1008.     
  1009.     RequirePtrAlignIfNotNil( current, 4 );
  1010.     return( current );
  1011. }
  1012.  
  1013. /****************************************************************************************
  1014.     Commenter    Date                Comment
  1015.     ---------    -----------------    -----------------------------------------------------
  1016.     wolf        Thu, Apr 15, 1999    Created.
  1017.     
  1018.     ************************************************************************************/
  1019.  
  1020.     pascal
  1021.     AtomicElement*
  1022. PeekAtomicQueue(
  1023.     AtomicQueue        *queue )
  1024. {
  1025.     AtomicElement    *result;
  1026.     
  1027.     RequirePtrAlign( queue, 4 );
  1028.     
  1029.     result = PopAtomicQueue( queue );
  1030.     
  1031.     if( result )
  1032.         PushAtomicStack( result, &queue->output );
  1033.     
  1034.     RequirePtrAlignIfNotNil( result, 4 );
  1035.     return( result );
  1036. }
  1037.  
  1038. /****************************************************************************************
  1039. *    
  1040. *    Atomic Queue Offset Functions
  1041. *    
  1042. ****************************************************************************************/
  1043. #pragma mark    -
  1044. #pragma mark    --Atomic Queue Offset Functions--
  1045.  
  1046. /****************************************************************************************
  1047.     Commenter    Date                Comment
  1048.     ---------    -----------------    -----------------------------------------------------
  1049.     wolf        Wed, Nov 25, 1998    Created.
  1050.     
  1051.     ************************************************************************************/
  1052.  
  1053.     pascal
  1054.     void
  1055. PushAtomicQueueOff(
  1056.     void            *element,
  1057.     AtomicQueue        *queue,
  1058.     size_t            offset )
  1059. {
  1060.     RequirePtr( element );
  1061.     Require( offset < 0xFFFF );
  1062.     RequirePtrAlign( queue, 4 );
  1063.     
  1064.     PushAtomicQueue( (AtomicElement*) (((char*) element) + offset), queue );
  1065. }
  1066.  
  1067. /****************************************************************************************
  1068.     Commenter    Date                Comment
  1069.     ---------    -----------------    -----------------------------------------------------
  1070.     wolf        Wed, Nov 25, 1998    Created.
  1071.     
  1072.     ************************************************************************************/
  1073.  
  1074.     pascal
  1075.     AtomicElement*
  1076. PopAtomicQueueOff(
  1077.     AtomicQueue        *queue,
  1078.     size_t            offset )
  1079. {
  1080.     AtomicElement    *result;
  1081.     
  1082.     Require( offset < 0xFFFF );
  1083.     RequirePtrAlign( queue, 4 );
  1084.     
  1085.     result = PopAtomicQueue( queue );
  1086.     
  1087.     if( result )
  1088.         result = (AtomicElement*) (((char*) result) - offset);
  1089.         
  1090.     RequirePtrAlignIfNotNil( result, 4 );
  1091.     return( result );
  1092. }
  1093.  
  1094. /****************************************************************************************
  1095.     Commenter    Date                Comment
  1096.     ---------    -----------------    -----------------------------------------------------
  1097.     wolf        Thu, Apr 15, 1999    Created.
  1098.     
  1099.     ************************************************************************************/
  1100.  
  1101.     pascal
  1102.     AtomicElement*
  1103. PeekAtomicQueueOff(
  1104.     AtomicQueue        *queue,
  1105.     size_t            offset )
  1106. {
  1107.     AtomicElement    *result;
  1108.     
  1109.     Require( offset < 0xFFFF );
  1110.     RequirePtrAlign( queue, 4 );
  1111.     
  1112.     result = PeekAtomicQueue( queue );
  1113.     
  1114.     if( result )
  1115.         result = (AtomicElement*) (((char*) result) - offset);
  1116.     
  1117.     RequirePtrAlignIfNotNil( result, 4 );
  1118.     return( result );
  1119. }
  1120.  
  1121. /****************************************************************************************
  1122. *    
  1123. *    Guarded Atomic Queue Functions
  1124. *    
  1125. ****************************************************************************************/
  1126. #pragma mark    -
  1127. #pragma mark    --Guarded Atomic Queue Functions--
  1128.  
  1129. /****************************************************************************************
  1130.     Commenter    Date                Comment
  1131.     ---------    -----------------    -----------------------------------------------------
  1132.     wolf        Mon, Nov 23, 1998    Created.
  1133.     
  1134.     ************************************************************************************/
  1135.  
  1136.     pascal
  1137.     long
  1138. PushGuardedAtomicQueue(
  1139.     GuardedAtomicElement    *element,
  1140.     AtomicQueue                *queue )
  1141. {
  1142.     RequirePtrAlign( element, 4 );
  1143.     RequirePtrAlign( queue, 4 );
  1144.     
  1145.     return( PushGuardedAtomicStack( element, &queue->input ) );
  1146. }
  1147.  
  1148. /****************************************************************************************
  1149.     Commenter    Date                Comment
  1150.     ---------    -----------------    -----------------------------------------------------
  1151.     wolf        Mon, Nov 23, 1998    Created.
  1152.     
  1153.     ************************************************************************************/
  1154.  
  1155.     pascal
  1156.     GuardedAtomicElement*
  1157. PopGuardedAtomicQueue(
  1158.     AtomicQueue                *queue )
  1159. {
  1160.     GuardedAtomicElement    *next, *current;
  1161.     
  1162.     RequirePtrAlign( queue, 4 );
  1163.     
  1164.     current = PopGuardedAtomicStack( &queue->output );
  1165.     
  1166.     if( current == nil ) {
  1167.         //    Nothing to pop. Refill the queue from the input stack.
  1168.         current = (GuardedAtomicElement*) StealAtomicStack( &queue->input );
  1169.         while( current ) {
  1170.             RequirePtrAlign( current, 4 );
  1171.             next = current->next;
  1172.             PushAtomicStack( (AtomicElement*) current, &queue->output );
  1173.             current = next;
  1174.         }
  1175.         current = PopGuardedAtomicStack( &queue->output );
  1176.     }
  1177.     
  1178.     RequirePtrAlignIfNotNil( current, 4 );
  1179.     return( current );
  1180. }
  1181.  
  1182. /****************************************************************************************
  1183.     Commenter    Date                Comment
  1184.     ---------    -----------------    -----------------------------------------------------
  1185.     wolf        Thu, Apr 15, 1999    Created.
  1186.     
  1187.     ************************************************************************************/
  1188.  
  1189.     pascal
  1190.     GuardedAtomicElement*
  1191. PeekGuardedAtomicQueue(
  1192.     AtomicQueue        *queue )
  1193. {
  1194.     GuardedAtomicElement    *next, *current;
  1195.     
  1196.     RequirePtrAlign( queue, 4 );
  1197.     
  1198.     if( queue->output.next == nil ) {
  1199.         //    Nothing to pop. Refill the queue from the input stack.
  1200.         current = (GuardedAtomicElement*) StealAtomicStack( &queue->input );
  1201.         while( current ) {
  1202.             RequirePtrAlign( current, 4 );
  1203.             next = current->next;
  1204.             PushAtomicStack( (AtomicElement*) current, &queue->output );
  1205.             current = next;
  1206.         }
  1207.     }
  1208.     
  1209.     return( (GuardedAtomicElement*) queue->output.next );
  1210. }
  1211.  
  1212. /****************************************************************************************
  1213. *    
  1214. *    Guarded Atomic Queue Offset Functions
  1215. *    
  1216. ****************************************************************************************/
  1217. #pragma mark    -
  1218. #pragma mark    --Guarded Atomic Queue Offset Functions--
  1219.  
  1220. /****************************************************************************************
  1221.     Commenter    Date                Comment
  1222.     ---------    -----------------    -----------------------------------------------------
  1223.     wolf        Wed, Nov 25, 1998    Created.
  1224.     
  1225.     ************************************************************************************/
  1226.  
  1227.     pascal
  1228.     long
  1229. PushGuardedAtomicQueueOff(
  1230.     void            *element,
  1231.     AtomicQueue        *queue,
  1232.     size_t            offset )
  1233. {
  1234.     RequirePtr( element );
  1235.     Require( offset < 0xFFFF );
  1236.     RequirePtrAlign( queue, 4 );
  1237.     
  1238.     return( PushGuardedAtomicQueue( (GuardedAtomicElement*) (((char*) element) + offset ),
  1239.                                 queue ) );
  1240. }
  1241.  
  1242. /****************************************************************************************
  1243.     Commenter    Date                Comment
  1244.     ---------    -----------------    -----------------------------------------------------
  1245.     wolf        Wed, Nov 25, 1998    Created.
  1246.     
  1247.     ************************************************************************************/
  1248.  
  1249.     pascal
  1250.     GuardedAtomicElement*
  1251. PopGuardedAtomicQueueOff(
  1252.     AtomicQueue        *queue,
  1253.     size_t            offset )
  1254. {
  1255.     GuardedAtomicElement    *result;
  1256.     
  1257.     Require( offset < 0xFFFF );
  1258.     RequirePtrAlign( queue, 4 );
  1259.     
  1260.     result = PopGuardedAtomicQueue( queue );
  1261.     
  1262.     if( result )
  1263.         result = (GuardedAtomicElement*) (((char*) result) - offset);
  1264.     
  1265.     RequirePtrAlignIfNotNil( result, 4 );
  1266.     return( result );
  1267. }
  1268.  
  1269. /****************************************************************************************
  1270.     Commenter    Date                Comment
  1271.     ---------    -----------------    -----------------------------------------------------
  1272.     wolf        Thu, Apr 15, 1999    Created.
  1273.     
  1274.     ************************************************************************************/
  1275.  
  1276.     pascal
  1277.     GuardedAtomicElement*
  1278. PeekGuardedAtomicQueueOff(
  1279.     AtomicQueue        *queue,
  1280.     size_t            offset )
  1281. {
  1282.     GuardedAtomicElement    *result;
  1283.     
  1284.     Require( offset < 0xFFFF );
  1285.     RequirePtrAlign( queue, 4 );
  1286.     
  1287.     result = PeekGuardedAtomicQueue( queue );
  1288.     
  1289.     if( result )
  1290.         result = (GuardedAtomicElement*) (((char*) result) - offset);
  1291.     
  1292.     RequirePtrAlignIfNotNil( result, 4 );
  1293.     return( result );
  1294. }